package com.gtcmu.skeye;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.InterruptedIOException;
import java.io.OutputStreamWriter;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;
import java.text.SimpleDateFormat;
import java.util.Date;

import android.os.Bundle;
import android.os.Environment;
import android.app.Activity;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.hardware.Camera;
import android.util.Log;
import android.view.Menu;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends Activity {

	Button mClickButton;
	Button mSendButton;
	ImageView mPicViewer;
	TextView mTextView;
	EditText mEditText;
	Camera mCamera;
    Preview mPreview;
    int cameraId = 0;
    ServerSocket mServerSocket;
    Socket mSocket;
    final int TCP_SERVER_PORT = 4444;
    PictureHandler mPictureHandler;
    String LOG_TAG = "Skeye";
    
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		
		mClickButton = (Button)findViewById(R.id.button1);
        mClickButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {            	
            	/* Click picture and show in image view */
            	mCamera.takePicture(null, null, mPictureHandler);
            }
        });
        
        mSendButton = (Button)findViewById(R.id.button2);
        mSendButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
            	/* Ask if other side is ready to recieve picture for further processing */
            	runTcpClientThread("Clicked");

            }
        });
		
        mPicViewer = (ImageView)findViewById(R.id.imageView1);
        
        mTextView = (TextView) findViewById(R.id.textView1); //main.xml has been modified
        
        mEditText = (EditText) findViewById(R.id.editText2);
        /* FIX ME Check if we need to do something here !!!
         * mEditText.setOnEditorActionListener(new TextView.OnEditorActionListener() {
                public boolean onEditorAction(TextView view, int actionId, KeyEvent event) {
                    
                }
            });*/
        startCamera();
        mPreview = new Preview(getApplicationContext(), mCamera); 
        FrameLayout preview = (FrameLayout) findViewById(R.id.cam_preview);
        preview.addView(mPreview);
       
        mPictureHandler = new PictureHandler(getApplicationContext(), mSocket, mCamera,mPicViewer);
	}
    
	private int findFrontFacingCamera() {
    	  int cameraId = -1;
    	    //FIX ME =  Search for the front facing camera
    	    /*int numberOfCameras = Camera.getNumberOfCameras();
    	    for (int i = 0; i < numberOfCameras; i++) {
    	      CameraInfo info = new CameraInfo();
    	      Camera.getCameraInfo(i, info);
    	      if (info.facing == CameraInfo.CAMERA_FACING_FRONT || info.facing == CameraInfo.CAMERA_FACING_BACK) {
    	        Log.d(DEBUG_TAG, "Camera found");
    	        cameraId = i;
    	        break;
    	      }
    	    }*/
    	    return 0;
    	  }
      
     private void startCamera()
      {
      	 if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA)) {
  			      Toast.makeText(this, "No camera on this device", Toast.LENGTH_LONG)
  			          .show();
  			    } else {
  			      cameraId = findFrontFacingCamera();
  			      if (cameraId < 0) {
  			        Toast.makeText(this, "No front facing camera found.",
  			            Toast.LENGTH_LONG).show();
  			      } else {
  			    	  mCamera = Camera.open(cameraId);
  			      }
      		}
      }
     
     @Override
     public void onResume() {
     	super.onResume();
     	if(mCamera == null)
     	{
 			mCamera = Camera.open(cameraId);
	 		// Have to start preview here
	 		mCamera.startPreview();
     	}
     }
     
     @Override
     protected void onStop() {
         super.onStop();
     	if(mCamera != null)
 		{
 			mCamera.stopPreview();
	 		mCamera.release();
	 		mCamera = null;
 		}
     }
     
     @Override
     protected void onDestroy() {
 		super.onDestroy();
     	if(mCamera != null)
     	{
     		mCamera.stopPreview();
     		mCamera.release();
     		mCamera = null;
     	}
    
     }
     
     @Override
 	protected void onPause() {
     	super.onPause();
 		// TODO Auto-generated method stub
 		if (mCamera != null) {
 			mCamera.stopPreview();
 			mCamera.release();
 			mCamera = null;
 		    }
 		
     }
     
     @Override
 	protected void onStart() {
 		// TODO Auto-generated method stub
 		super.onStart();

 	}
     
	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		// Inflate the menu; this adds items to the action bar if it is present.
		getMenuInflater().inflate(R.menu.activity_main, menu);
		return true;
	}
	
    void runTcpServerThread()
    {
    	new Thread(new Runnable() {
            public void run() {
            	runTcpServer();// do stuff that doesn't touch the UI here
            }
    }).start();
    }
    
    void runTcpServer() {
    	try {
			mServerSocket = new ServerSocket(TCP_SERVER_PORT);
			
			while(true){
			//accept connections
			mSocket = mServerSocket.accept();

			BufferedReader in = new BufferedReader(new InputStreamReader(mSocket.getInputStream()));
			         
			//receive a message
			String incomingMsg = in.readLine() + System.getProperty("line.separator");
			
			
			/* FIX ME : Receive picture data here and implement image processing if required */
			if(incomingMsg.equals("ready"+System.getProperty("line.separator")))
			{
				showMsgonui("Got Ready -- send picture !");
				mPictureHandler.sendPictureThread();
			}
			else if(incomingMsg.equals("clicked"+System.getProperty("line.separator")))
			{
				showMsgonui("Got clicked -- sending ready !");
				sendRequest("ready");
				
				getResponse(mSocket);
			}
			else
			{
				// It is picture
				showMsgonui("Unexpected packet recieved !");
				
			}
			
			//s.close();
			}
			
		} catch (InterruptedIOException e) {
			//if timeout occurs
			e.printStackTrace();
    	} catch (IOException e) {
			e.printStackTrace();
		} finally {
			if (mServerSocket != null) {
				try {
					mServerSocket.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
    }
    
    void runTcpClientThread(String str)
    {
    	final String arg = str;
    	  	new Thread(new Runnable() {
	            public void run() 
	            {sendRequest(arg);}
	         }).start();
    	
    }
    
    void sendRequest(String str) {
		 
    	try {
    		InetAddress serverAddr = InetAddress.getByName(mEditText.toString());
			Socket s = new Socket(serverAddr, TCP_SERVER_PORT);
			
			//BufferedReader in = new BufferedReader(new InputStreamReader(s.getInputStream()));
			BufferedWriter out = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));			
			//send output
			String outMsg = str + System.getProperty("line.separator"); 
			out.write(outMsg);
			out.flush();
			
			showMsgonui("sent: " + outMsg);	
			s.close();
			
		} catch (UnknownHostException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} 
    }
    
    public byte[] getPicture(InputStream in) {
        try {
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            int count = 0;
            int data;
            Log.i("TcpClient", "receiving ");
            while ((data = in.read())>=0) {
                out.write(data);
                count++;
            }
            Log.d("TcpClient", "recieved byte count "+Integer.toString(count));
            return out.toByteArray();
        } catch(IOException ioe) {
            //handle it
        	Log.i("TcpClient", "IO exception reading picture ");
        }
        Log.d("TcpClient", "recieved NOTHING ");
        return null;
    }
    
    void getResponse(Socket s)
    {
    	try{
	    	//accept server response	
			byte[] pic = getPicture(s.getInputStream());
			showMsgonui("Received picture");
			if(pic == null)
			{
				showMsgonui("Received NULL picture");
			}
			else
			{
				showMsgonui("Saving picture");
				savePic(pic);
				showMsgonui("Showing picture");
				showPic(pic);
				
			}

    	}catch (UnknownHostException e) 
    	{
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} 
    }
    
    void showPic(final byte[] arr)
    {
    	runOnUiThread(
				new Runnable()
				{	
					public void run() 
					{				
						Bitmap bmp=BitmapFactory.decodeByteArray(arr,0,arr.length);
						Bitmap resizedBitmap = Bitmap.createScaledBitmap(bmp, 1024, 1024, false);
						mPicViewer.setImageBitmap(resizedBitmap);
						mPicViewer.requestFocus();
						Log.i("TcpClient", "Shown image ");
						Toast.makeText(getApplicationContext(), "Shown Image", Toast.LENGTH_LONG).show();
					}
				}
				);
    }
    
    void savePic(byte[] data)
    {

    	File pictureFileDir = Environment.getExternalStoragePublicDirectory(
                Environment.DIRECTORY_PICTURES);
	    if (!pictureFileDir.exists() && !pictureFileDir.mkdirs()) {

	      Log.d(LOG_TAG, "Can't create directory to save image.");
	      Toast.makeText(getApplicationContext(), "Can't create directory to save image.",
	          Toast.LENGTH_LONG).show();
	      return;

	    }

	    SimpleDateFormat dateFormat = new SimpleDateFormat("yyyymmddhhmmss");
	    String date = dateFormat.format(new Date());
	    String photoFile = "Skeye_Picture_" + date + ".jpg";

	    String filename = pictureFileDir.getPath() + File.separator + photoFile;

	    File pictureFile = new File(filename);

	    try {
	      FileOutputStream fos = new FileOutputStream(pictureFile);
	      fos.write(data);
	      fos.close();
	      Toast.makeText(getApplicationContext(), "New Image saved:" + photoFile,
	          Toast.LENGTH_LONG).show();
	    } catch (Exception error) {
	      Log.d(LOG_TAG, "File" + filename + "not saved: "
	          + error.getMessage());
	      Toast.makeText(getApplicationContext(), "Image could not be saved.",Toast.LENGTH_LONG).show();
	    }
    }
    public void showMsgonui(final String str)
    {
    	runOnUiThread(
				new Runnable()
				{	
					public void run() 
					{
						Toast.makeText(getApplicationContext(), str, Toast.LENGTH_LONG).show();
						Log.i("LOG_TAG", str);
					}
				}
				);
    }

}
